//
// stacktrace.h
// libprotea
// Tools Library for the Protea Project / Functionality for managing stacktraces
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

#ifndef __PROTEA_STACKTRACE_H__
#define __PROTEA_STACKTRACE_H__

#include <stdlib.h>
#include "OSDep/process.h"

// Forward declaration of application interface
class XCAppInterface;


//
//  Stack trace utility
//
//		Uses C++ exception passing to track the callstack at the time the exception occurred
//



// Logs entrance/exit of routines
__EXPORT void XCInitProfiler();
__EXPORT void XCEnterSubroutine( XCAppInterface* app, const char* funcname );
__EXPORT void XCLeaveSubroutine( XCAppInterface* app, const char* funcname, const long linenum, const long result );
__EXPORT void XCProfilePoint( XCAppInterface* app, const char* info );

// Call stack functions
__EXPORT void XCAddFunction( const char *func_name, const int line, const char* file );
__EXPORT void XCOutputCallStack( XCAppInterface* app, int err_num, char* err_descr );
__EXPORT void XCClearCallStack();


//
// Macro definitions
//
#define ENTERFUNC() {if (TOOLSAPP && TOOLSAPP->TraceFunctions()) XCEnterSubroutine( TOOLSAPP, __TOOLS_FUNCTION__ ); };
#define LEAVEFUNC(result) if (TOOLSAPP && TOOLSAPP->TraceFunctions()) XCLeaveSubroutine( TOOLSAPP, __TOOLS_FUNCTION__, __LINE__, (long)result );



/// Tracks when function is entered

#ifdef INTERNAL_USE
#	define INFUNC(func,app) const char *__TOOLS_FUNCTION__ = #func; XCAppInterface* TOOLSAPP = app; try { ENTERFUNC();
#	define OUTFUNC() LEAVEFUNC(0) } catch( XCToolsError& error ) { LEAVEFUNC(-255); XCAddFunction( __TOOLS_FUNCTION__, error.GetLineNumber(), __FILE__); error.ClearLine(); throw; } catch(...) { XCAddFunction( __TOOLS_FUNCTION__, __LINE__, __FILE__); throw; }
#	define OUTFUNCRET(x) LEAVEFUNC(x) return x; } catch( XCToolsError& error ) { LEAVEFUNC(-255); XCAddFunction( __TOOLS_FUNCTION__, error.GetLineNumber(), __FILE__); error.ClearLine(); throw; } catch(...) { XCAddFunction( __TOOLS_FUNCTION__, __LINE__, __FILE__ ); throw; }
#	define RETURNFUNC(x) { LEAVEFUNC(x) return x; }
#	define EXITFUNC() { LEAVEFUNC(NULL) return; }
#else
#	define INFUNC(func,app) XCAppInterface* TOOLSAPP = app; try {
#	define OUTFUNC() } catch( ... ) { throw; };
#	define OUTFUNCRET(x) return x; } catch( ... ) { throw; };
#	define RETURNFUNC(x) {return x;}
#	define EXITFUNC() {return;}
#endif

#define EXT_INFUNC(func,app) const char *__TOOLS_FUNCTION__ = #func; XCAppInterface* TOOLSAPP = app; try { ENTERFUNC();
#define EXT_OUTFUNC() LEAVEFUNC(0) } catch( XCToolsError& error ) { LEAVEFUNC(-255); XCAddFunction( __TOOLS_FUNCTION__, error.GetLineNumber(), __FILE__); error.ClearLine(); throw; } catch(...) { XCAddFunction( __TOOLS_FUNCTION__, __LINE__, __FILE__); throw; }
#define EXT_OUTFUNCRET(x) LEAVEFUNC(x) return x; } catch( XCToolsError& error ) { LEAVEFUNC(-255); XCAddFunction( __TOOLS_FUNCTION__, error.GetLineNumber(), __FILE__); error.ClearLine(); throw; } catch(...) { XCAddFunction( __TOOLS_FUNCTION__, __LINE__, __FILE__ ); throw; }
#define EXT_RETURNFUNC(x) { LEAVEFUNC(x) return x; }
#define EXT_EXITFUNC() { LEAVEFUNC(NULL) return; }

#define TRANS_INFUNC(func) XCAppInterface* App = vars->myapp; EXT_INFUNC(func, App)
#define TRANS_OUTFUNC() EXT_OUTFUNC()
#define TRANS_OUTFUNCRET(x) EXT_OUTFUNCRET(x)
#define TRANS_RETURNFUNC(x) EXT_RETURNFUNC(x)
#define TRANS_EXITFUNC() EXT_EXITFUNC()

// Structure for maintaining performance counter information
STACKTRACE_PERF_FREQ;
struct tPerfCounters {
	STACKTRACE_COUNT_TYPE start;
	STACKTRACE_COUNT_TYPE end;
	tPerfCounters* next;
};


class __EXPORT XCTiming {
public:
	XCTiming();

	void Start();
	double Stop();

	double GetLast() { return last_result; };

	double GetCurrent();
	double GetStart();

private:
	double last_result;

	STACKTRACE_TIME_TYPE perf_freq;
	STACKTRACE_TIME_TYPE start;
	STACKTRACE_TIME_TYPE end;
	STACKTRACE_FREQ_TYPE freq;
};

#endif
